﻿#include "CTPTradeLib.h"
#include <list>
#include <string>
#include "Tools.h"
#include <fstream>
#include <iostream>
#include <thread>
#ifdef __linux__
#include <cstring>
#endif
#include "OptionManager.h"
#include "TradeBlocker.h"
#include "SymbolDetail.h"
#include "SymbolsSrc.h"
#include "TradeOrderIO.h"

CTPTradeLib::CTPTradeLib()
{
	std::string pflow = OptionManager::Instance().GetWorkDir() + "/Flow";
	m_api = CThostFtdcTraderApi::CreateFtdcTraderApi(pflow.c_str());
	m_tradeSpi = new TradeApiSpi(m_api);
	m_requestId = 0;
	m_account = {};
	m_TradeFeedFunc = nullptr;
	m_requestError = 0;
	// 设置成交回调
	m_tradeSpi->SetTradeBackFunc([this](CThostFtdcTradeField *pTrade) {
		std::string pSymbol = pTrade->InstrumentID;
		// 重新查询仓位
		std::thread thread([this, pSymbol]() {
			// 线程中休眠5s接着查询仓位
			std::this_thread::sleep_for(std::chrono::seconds(5));
			QueryPositions(pSymbol);
		});
		thread.detach();
		if (m_TradeFeedFunc != nullptr)
		{
			m_TradeFeedFunc(pSymbol, pTrade->Price, pTrade->TradeTime);
		}
		m_TradeFeedFunc = nullptr;
	});
}

CTPTradeLib::~CTPTradeLib()
{
	if (m_api != nullptr)
	{
		m_api->RegisterSpi(nullptr);
		m_api->Release();
	}
	if (m_tradeSpi != nullptr)
	{
		delete m_tradeSpi;
		m_tradeSpi = nullptr;
	}
}

void CTPTradeLib::Init()
{
	TradeOrderIO orderIO;
	orderIO.Read(m_orders);

	BlockerSmart ctpBlocker = Blocker::Create(20);
	m_tradeSpi->SetBlocker(ctpBlocker);
	// 注册回调
	m_api->RegisterSpi(m_tradeSpi);
	// 注册网络地址
	const std::list<std::string > &address = m_tradeSpi->GetCtpUsr().Trade_IPs;
	if (address.empty())
	{
		return;
	}
	for (auto iter = address.begin(); iter != address.end(); ++iter)
	{
		m_api->RegisterFront((char*)iter->c_str());
	}
	m_api->SubscribePublicTopic(THOST_TERT_RESTART);
	m_api->SubscribePrivateTopic(THOST_TERT_RESTART);
	// 初始化连接
	m_api->Init();
	
	ctpBlocker->BlockCTP();
}

void CTPTradeLib::Logout()
{
	CThostFtdcUserLogoutField req = { 0 };
	strncpy(req.BrokerID, m_tradeSpi->GetCtpUsr().User_BrokerID.c_str(), sizeof(req.BrokerID));
	strncpy(req.UserID, m_tradeSpi->GetCtpUsr().UserId.c_str(), sizeof(req.UserID));
	m_api->ReqUserLogout(&req, 500);
	printf("请求登出\n");
	BlockerSmart ctpBlocker = Blocker::Create(2);
	ctpBlocker->BlockCTP();
}

void CTPTradeLib::WaitForever()
{
	if (m_api != nullptr)
	{
		m_api->Join(); // 测试的时候才用
	}
}

void CTPTradeLib::InsertOrderNow(const TD::OrderOption &pOption, TD::OrderBackFunc pBackFunc)
{
	m_TradeFeedFunc = pBackFunc;
	if (pOption.Volumn == 0)
	{
		closeOrderNow(pOption.Symbol, pOption.TickCount, pOption.LastPrice);
	}
	else
	{
		openOrderNow(pOption.Symbol, pOption.Volumn, pOption.TickCount, pOption.LastPrice);
	}
	
}

void CTPTradeLib::QueryContracts()
{
	// 查询合约或手续费的回调
	BlockerSmart ctpBlocker = Blocker::Create(20);
	SymbolsSrc *psymbolRecorder = new SymbolsSrc();
	m_tradeSpi->SetRspQryInstrumentFunc([this, psymbolRecorder, ctpBlocker](CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
		psymbolRecorder->AppendSymbol(pInstrument);
		if (bIsLast)
		{
			psymbolRecorder->SaveSymbols();
			delete psymbolRecorder;
			printf("合约列表下载完成\n");
			Blocker::Stop(ctpBlocker);
		}
		//printf("下载合约 %s\n", pInstrument->InstrumentID);
	});

	// 合约下载
	CThostFtdcQryInstrumentField req;
	memset(&req, 0, sizeof(req));
	//strcpy(req.InstrumentID, INSTRUMENT_ID);  //只要注释掉这一句，就可以实现全合约的查询了，这一句的作用是查询我们指定的合约信息
	int iResult = m_api->ReqQryInstrument(&req, 115);
	printf("下载合约列表--iResult: %d\n", iResult);
	ctpBlocker->BlockCTP();
}

void CTPTradeLib::QueryPositions(const std::string &psymbol, QryData::QryBackFunc qryFunc)
{
	BlockerSmart ctpBlocker = Blocker::Create(20);
	m_tradeSpi->SetRspQryInvestorPositionFunc([this, ctpBlocker, qryFunc](CThostFtdcInvestorPositionField *position, CThostFtdcRspInfoField *rsp_info, int req_id, bool is_last) {
		if (position == nullptr)
		{
			if (qryFunc != nullptr)
			{
				qryFunc(QryData::Qry_Position);
			}
			return;
		}
		std::map<std::string, QryData::Position>::iterator it = m_symbolPOsition.find(position->InstrumentID);
		if (position->Position <= 0)
		{
			if (it != m_symbolPOsition.end())
			{
				printf("合约 %s 取消持仓\n", position->InstrumentID);
				m_symbolPOsition.erase(it);
			}
			if (qryFunc != nullptr)
			{
				qryFunc(QryData::Qry_Position);
			}
			return;
		}
		auto &poses = m_symbolPOsition[position->InstrumentID];
		bool is_long_pos = position->PosiDirection == THOST_FTDC_PD_Long;
		poses.poses.emplace_back(QryData::PositionDetail());
		QryData::PositionDetail &pdetail = poses.poses.back();
		pdetail.isLong = is_long_pos;
		if (position->PositionDate == THOST_FTDC_PSD_Today)
		{
			pdetail.isYd = false;
			pdetail.holdings = position->Position;
		}
		else if (position->PositionDate == THOST_FTDC_PSD_History)
		{
			pdetail.isYd = true;
			pdetail.holdings = position->Position - position->TodayPosition;
		}
		printf("合约 %s %s %s %d手\n", position->InstrumentID, is_long_pos ? "多头" : "空头", pdetail.isYd ? "昨仓" : "今仓", pdetail.holdings);

		//auto &pos_detail = is_long_pos ? pos.long_pos : pos.short_pos;
		//pdetail.holdings = position->Position;
		//pos_detail.yd_holdings = position->Position - position->TodayPosition;
		pdetail.float_pnl = position->PositionProfit;

		if (is_long_pos)
			pdetail.frozen = position->LongFrozen;
		else
			pdetail.frozen = position->ShortFrozen;
		if (is_last)
		{
			Blocker::Stop(ctpBlocker);
		}
		if (qryFunc != nullptr)
		{
			qryFunc(QryData::Qry_Position);
		}
		// todo 暂时先不计算
		//if (pos_detail.holdings > 0 && contract->VolumeMultiple > 0)
		//	pos_detail.cost_price = position->PositionCost / (pos_detail.holdings * contract->size);
	});
	CThostFtdcQryInvestorPositionField req{};
	strncpy(req.BrokerID, m_tradeSpi->GetCtpUsr().User_BrokerID.c_str(), sizeof(req.BrokerID));
	strncpy(req.InvestorID, m_tradeSpi->GetCtpUsr().U_InvestorID.c_str(), sizeof(req.InvestorID));
	
	if (!psymbol.empty())
	{
		strncpy(req.InstrumentID, psymbol.c_str(), sizeof(req.InstrumentID));  //只要注释掉这一句，就可以实现全合约的查询了，这一句的作用是查询我们指定的合约信息
		auto &poses = m_symbolPOsition[psymbol];
		poses.poses.clear();
	}
	else
	{
		m_symbolPOsition.clear();
	}
	int res = m_api->ReqQryInvestorPosition(&req, 200);
	printf("查询仓位--%d\n", res);
	m_requestError = res;
	ctpBlocker->BlockCTP();
}

void CTPTradeLib::QueryAccount()
{
	BlockerSmart ctpBlocker = Blocker::Create(2);
	m_tradeSpi->SetRspQryTradingAccountFunc([this, ctpBlocker](CThostFtdcTradingAccountField *trading_account, CThostFtdcRspInfoField *rsp_info, int req_id, bool is_last) {
		if (!is_last) return;
		if (trading_account == nullptr)
		{
			return;
		}
		m_account.account_id = std::stoul(trading_account->AccountID);
		m_account.total_asset = trading_account->Balance;
		m_account.margin = trading_account->CurrMargin;
		m_account.frozen = trading_account->FrozenCash + trading_account->FrozenMargin +
			trading_account->FrozenCommission;
		m_account.cash = m_account.total_asset - m_account.margin - m_account.frozen;
		Blocker::Stop(ctpBlocker);
	});

	CThostFtdcQryTradingAccountField req{};
	strncpy(req.BrokerID, m_tradeSpi->GetCtpUsr().User_BrokerID.c_str(), sizeof(req.BrokerID));
	strncpy(req.InvestorID, m_tradeSpi->GetCtpUsr().U_InvestorID.c_str(), sizeof(req.InvestorID));

	int res = m_api->ReqQryTradingAccount(&req, 201);
	printf("查询账户--%d\n", res);
	ctpBlocker->BlockCTP();
	m_requestError = res;
}

void CTPTradeLib::QueryTrades()
{

	CThostFtdcQryTradeField req{};
	strncpy(req.BrokerID, m_tradeSpi->GetCtpUsr().User_BrokerID.c_str(), sizeof(req.BrokerID));
	strncpy(req.InvestorID, m_tradeSpi->GetCtpUsr().U_InvestorID.c_str(), sizeof(req.InvestorID));

	int res = m_api->ReqQryTrade(&req, 202);
	printf("查询交易%d\n", res);
	// 查询后好像没有什么用
	BlockerSmart ctpBlocker = Blocker::Create(5);
	ctpBlocker->BlockCTP();
	m_requestError = res;
}

void CTPTradeLib::QueryOrders()
{
	CThostFtdcQryOrderField req{};
	strncpy(req.BrokerID, m_tradeSpi->GetCtpUsr().User_BrokerID.c_str(), sizeof(req.BrokerID));
	strncpy(req.InvestorID, m_tradeSpi->GetCtpUsr().U_InvestorID.c_str(), sizeof(req.InvestorID));

	int res = m_api->ReqQryOrder(&req, 203);
	printf("查询下单--%d\n", res);
	BlockerSmart ctpBlocker = Blocker::Create(5);
	ctpBlocker->BlockCTP();
	m_requestError = res;
}

//void CTPModel::SetFeedbackFunc(TD::OrderBackFunc pTradeFeedFunc)
//{
//	m_TradeFeedFunc = pTradeFeedFunc;
//}

void CTPTradeLib::openOrderNow(const std::string &pSymbol, int volumn, int tickCount, float lastPrice)
{
	if (volumn == 0)
	{
		return;
	}
	SymbolPackage::SymbolsReader sReader(Tools::GetCurrentTimeStamp());
	SymbolPackage::SymbolInfo pInfo = sReader.GetSymbolInfo(pSymbol);
	std::string pExchangeId = pInfo.ExchangeID;
	if (volumn > 0)
	{
		sendOrder(pExchangeId, pSymbol, abs(volumn), lastPrice + tickCount * pInfo.PriceTick, THOST_FTDC_D_Buy, THOST_FTDC_OF_Open);
	}
	else if (volumn < 0)
	{
		sendOrder(pExchangeId, pSymbol, abs(volumn), lastPrice - tickCount * pInfo.PriceTick, THOST_FTDC_D_Sell, THOST_FTDC_OF_Open);
	}
}

void CTPTradeLib::closeOrderNow(const std::string &pSymbol, int tickCount, float lastPrice)
{
	// 查询原始仓位
	std::map<std::string, QryData::Position>::iterator itSymbol = m_symbolPOsition.find(pSymbol);
	if (itSymbol == m_symbolPOsition.end())
	{
		return;
	}
	SymbolPackage::SymbolsReader sReader(Tools::GetCurrentTimeStamp());
	SymbolPackage::SymbolInfo pInfo = sReader.GetSymbolInfo(pSymbol);
	std::string pExchangeId = pInfo.ExchangeID;
	for (std::list<QryData::PositionDetail>::iterator it = itSymbol->second.poses.begin(); it != itSymbol->second.poses.end(); ++it)
	{
		TThostFtdcDirectionType pDir = it->isLong ? THOST_FTDC_D_Sell : THOST_FTDC_D_Buy;
		float orderPrice = it->isLong ? lastPrice - tickCount * pInfo.PriceTick : lastPrice + tickCount * pInfo.PriceTick;
		char CombOffsetFlag = it->isYd ? THOST_FTDC_OF_CloseYesterday : THOST_FTDC_OF_CloseToday;
		sendOrder(pExchangeId, pSymbol, it->holdings, orderPrice, pDir, CombOffsetFlag);
	}
}

void CTPTradeLib::sendOrder(const std::string &pExchangeId, const std::string &pSymbol, int volumn, float orderPrice, TThostFtdcDirectionType pDir, char CombOffsetFlag)
{
	CThostFtdcInputOrderField req{};
	strncpy(req.BrokerID, m_tradeSpi->GetCtpUsr().User_BrokerID.c_str(), sizeof(req.BrokerID));
	strncpy(req.InvestorID, m_tradeSpi->GetCtpUsr().U_InvestorID.c_str(), sizeof(req.InvestorID));
	strncpy(req.InstrumentID, pSymbol.c_str(), sizeof(req.InstrumentID));
	strncpy(req.ExchangeID, pExchangeId.c_str(), sizeof(req.ExchangeID));
	//snprintf(req.OrderRef, sizeof(req.OrderRef), "%lu", order_ref);
	req.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
	req.Direction = pDir;
	req.CombOffsetFlag[0] = CombOffsetFlag;
	req.LimitPrice = orderPrice;
	req.VolumeTotalOriginal = volumn;
	req.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	req.ContingentCondition = THOST_FTDC_CC_Immediately;
	req.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
	req.MinVolume = 1;
	req.IsAutoSuspend = 0;
	req.UserForceClose = 0;
	req.TimeCondition = THOST_FTDC_TC_IOC;
	req.VolumeCondition = THOST_FTDC_VC_AV;

	int res = m_api->ReqOrderInsert(&req, 205);
	printf("合约 %s %s %s 价格:%4f-- ReqOrderInsert请求 返回%d\n", 
		pSymbol.c_str(), 
		pDir == THOST_FTDC_D_Buy ? "多头" : "空头",
		CombOffsetFlag == THOST_FTDC_OF_Open ? "开仓" : "平仓",
		orderPrice,
		res);
}

bool CTPTradeLib::IsPositionEmpty(const std::string &pSymbol)
{
	std::map<std::string, QryData::Position>::iterator it = m_symbolPOsition.find(pSymbol);
	if (it == m_symbolPOsition.end())
	{
		return false;
	}
	bool hasOrder = false;
	for (std::list<QryData::PositionDetail>::iterator itOrder = it->second.poses.begin(); itOrder != it->second.poses.end(); ++itOrder)
	{
		if (itOrder->holdings > 0)
		{
			hasOrder = true;
			break;
		}
	}
	return hasOrder;
}

bool CTPTradeLib::GetPositionDetail(const std::string &pSymbol, QryData::Position &outPos)
{
	std::map<std::string, QryData::Position>::iterator it = m_symbolPOsition.find(pSymbol);
	if (it == m_symbolPOsition.end())
	{
		return false;
	}
	outPos = it->second;
	return true;
}

bool CTPTradeLib::GetOrderDetail(const std::string &pSymbol, TD::Order &outOrder)
{
	std::map<std::string, TD::Order>::iterator it = m_orders.find(pSymbol);
	if (it == m_orders.end())
	{
		return false;
	}
	outOrder = it->second;
	return true;
}

bool CTPTradeLib::UpdateOrderDetail(const std::string &pSymbol, const TD::Order &pOrder)
{
	m_orders[pSymbol] = pOrder;
	TradeOrderIO orderIO;
	orderIO.Save(m_orders);
	return true;
}

bool CTPTradeLib::EraseOrderDetail(const std::string &pSymbol)
{
	if (m_orders.empty())
	{
		return false;
	}
	std::map<std::string, TD::Order>::iterator itOrder = m_orders.find(pSymbol);
	if (itOrder == m_orders.end())
	{
		return false;
	}
	m_orders.erase(itOrder);
	TradeOrderIO orderIO;
	orderIO.Save(m_orders);
	return true;
}

